package com.zx._09_架构.扩展性.cpt1_event;

import com.zx._09_架构.扩展性.cpt1_event.event.Event;
import com.zx._09_架构.扩展性.cpt1_event.handler.EventHandler;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class EventHandlerManager {

    private static Map<String, EventHandler> HANDLER_MAP = new HashMap<>();

    public static void init() throws Exception {
        List<Class<?>> implementations = getInterfaceImplementations(EventHandler.class);
        for (Class<?> implClass : implementations) {
            EventHandler handler = (EventHandler) implClass.getDeclaredConstructor().newInstance();
            String paramTypeName = handler.paramType().getName();
            HANDLER_MAP.put(paramTypeName, handler);
        }
    }

    /**
     * 发布事件
     *
     * @param event
     * @return
     */
    public static boolean publicEvent(Event event) {
        EventHandler handler = HANDLER_MAP.get(event.getClass().getName());
        return handler.on(event);
    }

    public static List<Class<?>> getInterfaceImplementations(Class<?> interfaceClass) {
        List<Class<?>> implementations = new ArrayList<>();
        String packageName = interfaceClass.getPackage().getName();
        try {
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            Enumeration<URL> resources = classLoader.getResources(packageName.replace('.', '/'));
            while (resources.hasMoreElements()) {
                URL resource = resources.nextElement();
                File file = new File(resource.getFile());
                if (file.isDirectory()) {
                    List<Class<?>> classes = getClasses(packageName, file);
                    for (Class<?> clazz : classes) {
                        if (interfaceClass.isAssignableFrom(clazz) && !interfaceClass.equals(clazz)) {
                            implementations.add(clazz);
                        }
                    }
                }
            }
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        return implementations;
    }

    private static List<Class<?>> getClasses(String packageName, File directory) throws ClassNotFoundException {
        List<Class<?>> classes = new ArrayList<>();
        File[] files = directory.listFiles();
        if (files != null) {
            for (File file : files) {
                if (file.isDirectory()) {
                    classes.addAll(getClasses(packageName + "." + file.getName(), file));
                } else if (file.getName().endsWith(".class")) {
                    String className = packageName + "." + file.getName().substring(0, file.getName().length() - 6);
                    Class<?> clazz = Class.forName(className);
                    classes.add(clazz);
                }
            }
        }
        return classes;
    }


}
